import { _decorator, Component, Node, Collider2D, Contact2DType } from 'cc';
import { Unit } from '../Unit';
import GameEventMgr, { GameEvent } from '../../Model/GameEventMgr';
import { Global, LootType, UnitType } from '../../Util/Global';
import { Bullet } from '../Bullet';
import { Bullet_3 } from '../Bullet_3';
import { UICtrl } from '../../Ctrl/UICtrl';
import { GameStickerType } from '../../Model/GameStickerMgr';
const { ccclass, property } = _decorator;

/**经济组件 */
@ccclass('EconomicCom')
export class EconomicCom extends Component {

    /**最大电容 最大输出功率*/
    public electric_power_max: number = 100;
    /**电力储配 电力输出盈余 储配小于0时无法生产单位*/
    public electric_power_remain: number = 0;
    /**矿物资源 */
    public mine_res: number = 100;

    public consumers: Set<Unit> = new Set();
    /**电力输出 */
    private _power_out: number = 0;

    protected unit: Unit = null;

    public damageTickTime: number = 0;

    /**电力负荷百分比 */
    get power_load() {
        let load = this.electric_power_remain <= 0 ?
            1 : (this._power_out + this.power_out_extra_frame) / this.electric_power_remain;
        return load;
    }

    /**每帧电力消耗 */
    get power_out() {
        return this._power_out + this.power_out_extra_frame;
    }

    private _power_out_extra_frame: number = 0;
    private _pre_power_out_extra_frame: number = 0;
    get power_out_extra_frame() {
        return this._power_out_extra_frame || this._pre_power_out_extra_frame;
    }

    AddPowerOutExtraFrame(num: number) {
        this._power_out_extra_frame += num;
    }

    start() {
        this.unit = this.getComponent(Unit);

        // 监听传感器碰撞事件
        this.unit.collider.on(Contact2DType.BEGIN_CONTACT, this.onColliderEnter, this);
    }

    protected onDisable(): void {
        // this.mine_res = 100;
        // this.consumers.clear();

        this.destroy();
    }

    update(deltaTime: number) {
        if (Global.gameManager.pause) {
            return;
        }
        this._pre_power_out_extra_frame = this._power_out_extra_frame;

        //消耗电量
        let out_power = this._power_out + this._power_out_extra_frame;
        this._power_out_extra_frame = 0;
        //需要发出的电力
        let need_power = out_power + (this.electric_power_max - this.electric_power_remain);
        //实际发出的电力
        let power = Math.min(need_power, this.electric_power_max);

        //消耗矿量
        let out_res = power / 10 * deltaTime;
        this.mine_res = this.mine_res - out_res;//用矿物维持电力输出
        this.mine_res = Math.max(0, this.mine_res);

        if (this.mine_res == 0 && this.unit.playerCtrl) {//没矿发电了 人机没矿也能发电
            power = 0;
        }

        //被攻击时输出的电力无法有效利用
        if (this.damageTickTime > 0) {
            this.damageTickTime -= deltaTime;
            power = 0;
        }

        let powerDt = deltaTime * (power - out_power);//电力供需差 结余
        // if (this.electric_power_remain > 0 && this.electric_power_remain + powerDt <= 0) {//破防！！
        //     GameEventMgr.Dispatch(GameEvent.EconomicComBroken, this.unit);
        // }

        this.electric_power_remain += powerDt;//储配电力
        this.electric_power_remain = Math.min(this.electric_power_max, this.electric_power_remain);
        this.electric_power_remain = Math.max(-out_power, this.electric_power_remain);
    }

    /**增加矿物资源 */
    AddMineRes(num: number = 0) {
        this.mine_res += num;
    }

    CostRes(num: number) {
        this.mine_res -= num;
    }

    /**
     * 是否可以生产这个单位
     * @param unit 单位
     * @param producingCost 真正建造的所有单位将要占用的电力负载
     * @returns 是否足够
     */
    HasUnitRes(unit: Unit, producingCost: number, sendFailedReason = false): boolean {
        if (this.mine_res > unit.spawn_cost) {//资源足够、电力功率富余
            if (this.electric_power_remain > 0 && this.power_load + producingCost / this.electric_power_remain < 1) {
                return true;
            }

            if (sendFailedReason && this.unit == Global.gameManager.playerUnit) {
                GameEventMgr.Dispatch(GameEvent.FactoryConstructionFailed, 'no_elec');
            }
            return false;
        }

        if (sendFailedReason && this.unit == Global.gameManager.playerUnit) {
            GameEventMgr.Dispatch(GameEvent.FactoryConstructionFailed, 'no_mine');
        }
        return false;
    }

    /**
     * 是否可以生产
     * @param unit 单位
     * @param producingPowerNeed 真正建造的所有单位将要占用的电力负载
     * @returns 是否足够
     */
    HasRes(need: number, producingPowerNeed: number): boolean {
        if (this.mine_res >= need) {//资源足够、电力功率富余
            if (this.electric_power_remain > 0 && this.power_load + producingPowerNeed / this.electric_power_remain < 1) {
                return true;
            }
            return false;
        }
        return false;
    }

    /**用电种类统计 */
    public consumers_map: Map<UnitType, number> = new Map;

    /**增加用电设备 */
    AddPowerConsumer(unit: Unit) {
        this.consumers.add(unit);
        if (unit.unitType < UnitType.UnitSpacecra && unit.unitType >= UnitType.UnitAssault) {
            let num = this.consumers_map.get(unit.unitType) || 0;
            this.consumers_map.set(unit.unitType, ++num);
        }
        this._power_out = this.CalculatePowerCost();
    }

    /**取消用电设备 */
    RemovePowerConsumer(unit: Unit) {
        this.consumers.delete(unit);

        if (unit.unitType < UnitType.UnitSpacecra && unit.unitType >= UnitType.UnitAssault) {
            let num = this.consumers_map.get(unit.unitType) || 1;
            this.consumers_map.set(unit.unitType, --num);
        }
        this._power_out = this.CalculatePowerCost();
    }

    /**计算电力消费 */
    CalculatePowerCost() {
        let sum = 0;
        for (const unit of this.consumers) {
            sum += unit.power_cost;
        }
        return sum;
    }

    protected onColliderEnter(selfCollider: Collider2D, otherCollider: Collider2D) {
        let other = otherCollider.node.getComponent(Unit);

        this.OnHitDamage(other);
    }

    OnHitDamage(from: Unit) {
        if (this.unit && !this.unit.death) {
            //要求没有伤害组件
            if (from && from.unitType == UnitType.Bullet && !this.unit.destructable) {

                if (this.unit.isInScreenPos) {
                    Global.gameManager.mapCtrl.mapSpawner.
                        SpawnUnitImmediatelyLoot(LootType.Electric, this.unit.unitWorldPos, 1);
                }

                if (this.electric_power_remain < 0) {
                    GameEventMgr.Dispatch(GameEvent.EconomicComBroken, this.unit);
                }

                if (from.parentUnit != this.unit) {
                    //被击中了！！
                    let bullet = <Bullet>from;
                    let b3 = from as Bullet_3;

                    let atk = bullet._atk;
                    if (b3.getMarkCount) {
                        let count = b3.getMarkCount(this.unit, this);
                        if (count == 0) {//初次触发
                            if (this.unit.isInScreenPos) {
                                Global.gameManager.mapCtrl.mapSpawner.
                                    SpawnUnitImmediatelyLoot(LootType.Electric, this.unit.unitWorldPos, 10);
                            }
                            b3.markTrigger(this.unit, this);

                            //防止玩家被秒杀 针对氦闪
                            if (this.unit.playerCtrl) {
                                GameEventMgr.Dispatch(GameEvent.ECViewDataChangeToTip, 'elec', -this.electric_power_remain);
                                this.electric_power_remain = Math.min(1, this.electric_power_remain);
                                atk = 0;
                            }
                        }
                        else if (b3.damageType == 1) {//单次伤害 已经触发过了
                            atk = 0;
                        }
                    }
                    else if (this.unit.playerCtrl) {
                        GameEventMgr.Dispatch(GameEvent.ECViewDataChangeToTip, 'elec', -atk);
                    }

                    this.electric_power_remain -= atk;
                    this.damageTickTime = 1;

                    if (!this.unit.playerCtrl && this.unit.isInScreenPos) {
                        UICtrl.CreateStickerRenderer(this.unit, GameStickerType.PlanetEconomicSticker);
                    }
                }
            }
        }
    }
}


